Purpose:

Runs survival analysis models using splicing cluster assignment and 1) single exon splicing burden index (SBI) 2) KEGG Spliceosome GSVA scores or 3) CLK1 exon 4 TPM as a predictor

Usage

Uses a wrapper function (survival_analysis) from utils folder.

Setup

Packages and functions

Load packages, set directory paths and call setup script

library(tidyverse)
library(survival)
library(ggpubr)
library(ggplot2)
library(patchwork)

root_dir <- rprojroot::find_root(rprojroot::has_dir(\.git\))

data_dir <- file.path(root_dir, \data\)
analysis_dir <- file.path(root_dir, \analyses\, \survival\)
input_dir <- file.path(analysis_dir, \results\)
results_dir <- file.path(analysis_dir, \results\)
plot_dir <- file.path(analysis_dir, \plots\)

# If the input and results directories do not exist, create it
if (!dir.exists(results_dir)) {
  dir.create(results_dir, recursive = TRUE)
}

source(file.path(analysis_dir, \util\, \survival_models.R\))
knitr::opts_chunk$set(cache = FALSE)

Set metadata and cluster assignment file paths

metadata_file <- file.path(input_dir, \splicing_indices_with_survival.tsv\)

cluster_file <- file.path(root_dir, \analyses\,
                          \sample-psi-clustering\, \results\,
                          \sample-cluster-metadata-top-5000-events-stranded.tsv\)

kegg_scores_stranded_file <- file.path(root_dir, \analyses\,
                          \sample-psi-clustering\, \results\,
                          \gsva_output_stranded.tsv\)

tpm_file <- file.path(data_dir, \rna-isoform-expression-rsem-tpm.rds\)
clk1_psi_file <- file.path(root_dir, 
                           \analyses\, 
                           \CLK1-splicing_correlations\, 
                           \results\, 
                           \clk1-exon4-psi.tsv\)

Wrangle data Add cluster assignment and spliceosome gsva scores to metadata and define column lgg_group (LGG or non_LGG)

metadata <- read_tsv(metadata_file)
clusters <- read_tsv(cluster_file) %>%
  dplyr::rename(Kids_First_Biospecimen_ID = sample_id)
clk1_psi <- read_tsv(clk1_psi_file) %>%
  dplyr::rename(CLK1_ex4_PSI = PSI) %>%
  select(-plot_group)
gsva_scores <- read_tsv(kegg_scores_stranded_file) %>%
  dplyr::filter(geneset == \KEGG_SPLICEOSOME\) %>%
  dplyr::rename(spliceosome_gsva_score = score)
all_clk4_transcr_counts <- readRDS(tpm_file) %>%
  filter(grepl(\^CLK1\, gene_symbol)) %>%
  mutate(
    transcript_id = case_when(
      transcript_id %in% c(\ENST00000321356.9\, \ENST00000434813.3\, \ENST00000409403.6\) ~ \Exon 4\,
      # transcript_id == \ENST00000321356.9\ ~ \Exon 4\,
      TRUE ~ \Other\
    )
  ) %>%
  group_by(transcript_id) %>%
  summarise(across(starts_with(\BS\), sum, na.rm = TRUE)) %>%
  pivot_longer(cols = -transcript_id, names_to = \Kids_First_Biospecimen_ID\, values_to = \CLK1_Ex4_TPM\) %>%
  filter(transcript_id == \Exon 4\) %>%
  inner_join(clusters, by = \Kids_First_Biospecimen_ID\) %>%
  left_join(clk1_psi)
# how many clusters?
n_clust <- length(unique(clusters$cluster))

metadata <- metadata %>%
  right_join(all_clk4_transcr_counts %>% dplyr::select(Kids_First_Biospecimen_ID,
                                       cluster, CLK1_Ex4_TPM, CLK1_ex4_PSI)) %>%
  left_join(gsva_scores %>% dplyr::select(sample_id,
                                          spliceosome_gsva_score),
            by = c(\Kids_First_Biospecimen_ID\ = \sample_id\)) %>% 
  dplyr::mutate(cluster = glue::glue(\Cluster {cluster}\)) %>%
  # dplyr::mutate(cluster = fct_relevel(cluster,
  #                                             paste0(\Cluster \, 1:n_clust))) %>%
  dplyr::mutate(cluster = forcats::fct_relevel(cluster, \Cluster 6\, after = 0)) %>%
  dplyr::mutate(lgg_group = case_when(
    plot_group == \Low-grade glioma\ ~ \LGG\,
    TRUE ~ \non-LGG\
  )) %>%
  dplyr::mutate(SBI = SI_Total * 10) %>%
  dplyr::mutate(age_at_diagnosis_years = age_at_diagnosis_days/365.25)

Generate coxph models including extent of tumor resection, lgg group, cluster assignment, SBI, and CLK1 exon 4 TPM as covariates

add_model_os <- fit_save_model(metadata[!metadata$extent_of_tumor_resection %in% c(\Not Reported\, \Unavailable\),],
                              terms = \extent_of_tumor_resection+lgg_group+cluster+age_at_diagnosis_years+SBI+CLK1_Ex4_TPM\,
                               file.path(results_dir, \cox_OS_additive_terms_resection_lgg_group_cluster_SBI_CLK1_Ex4_TPM.RDS\),
                               \multivariate\,
                               years_col = \OS_years\,
                               status_col = \OS_status\)

forest_os <- plotForest(readRDS(file.path(results_dir, \cox_OS_additive_terms_resection_lgg_group_cluster_SBI_CLK1_Ex4_TPM.RDS\)))

forest_os

ggsave(file.path(plot_dir, \forest_add_OS_resection_lgg_group_cluster_assignment_SBI_CLK1_Ex4_TPM.pdf\),
       forest_os,
       width = 10, height = 6, units = \in\,
       device = \pdf\)

add_model_efs <- fit_save_model(metadata[!metadata$extent_of_tumor_resection %in% c(\Not Reported\, \Unavailable\),],
                              terms = \extent_of_tumor_resection+lgg_group+cluster+age_at_diagnosis_years+SBI+CLK1_Ex4_TPM\,
                               file.path(results_dir, \cox_EFS_additive_terms_resection_lgg_group_cluster_SBI_CLK1_Ex4_TPM.RDS\),
                               \multivariate\,
                               years_col = \EFS_years\,
                               status_col = \EFS_status\)

forest_efs <- plotForest(readRDS(file.path(results_dir, \cox_EFS_additive_terms_resection_lgg_group_cluster_SBI_CLK1_Ex4_TPM.RDS\)))

forest_efs

ggsave(file.path(plot_dir, \forest_add_EFS_resection_lgg_group_cluster_assignment_SBI_CLK1_Ex4_TPM.pdf\),
       forest_efs,
       width = 10, height = 6, units = \in\,
       device = \pdf\)

repeat analysis with CLK1 exon 4 TPM alone

add_model_os <- fit_save_model(metadata[!metadata$extent_of_tumor_resection %in% c(\Not Reported\, \Unavailable\),],
                              terms = \extent_of_tumor_resection+lgg_group+cluster+age_at_diagnosis_years+CLK1_Ex4_TPM\,
                               file.path(results_dir, \cox_OS_additive_terms_resection_lgg_group_cluster_CLK1_Ex4_TPM.RDS\),
                               \multivariate\,
                               years_col = \OS_years\,
                               status_col = \OS_status\)

forest_os <- plotForest(readRDS(file.path(results_dir, \cox_OS_additive_terms_resection_lgg_group_cluster_CLK1_Ex4_TPM.RDS\)))

forest_os

ggsave(file.path(plot_dir, \forest_add_OS_resection_lgg_group_cluster_assignment_CLK1_Ex4_TPM.pdf\),
       forest_os,
       width = 10, height = 6, units = \in\,
       device = \pdf\)


add_model_efs <- fit_save_model(metadata[!metadata$extent_of_tumor_resection %in% c(\Not Reported\, \Unavailable\),],
                              terms = \extent_of_tumor_resection+lgg_group+cluster+age_at_diagnosis_years+CLK1_Ex4_TPM\,
                               file.path(results_dir, \cox_EFS_additive_terms_resection_lgg_group_cluster_CLK1_Ex4_TPM.RDS\),
                               \multivariate\,
                               years_col = \EFS_years\,
                               status_col = \EFS_status\)

forest_efs <- plotForest(readRDS(file.path(results_dir, \cox_EFS_additive_terms_resection_lgg_group_cluster_CLK1_Ex4_TPM.RDS\)))

forest_efs

ggsave(file.path(plot_dir, \forest_add_EFS_resection_lgg_group_cluster_assignment_CLK1_Ex4_TPM.pdf\),
       forest_efs,
       width = 10, height = 6, units = \in\,
       device = \pdf\)

repeat analysis with CLK1 exon 4 PSI

add_model_os <- fit_save_model(metadata[!metadata$extent_of_tumor_resection %in% c(\Not Reported\, \Unavailable\),],
                              terms = \extent_of_tumor_resection+lgg_group+cluster+age_at_diagnosis_years+CLK1_ex4_PSI\,
                               file.path(results_dir, \cox_OS_additive_terms_resection_lgg_group_cluster_CLK1_ex4_PSI.RDS\),
                               \multivariate\,
                               years_col = \OS_years\,
                               status_col = \OS_status\)

forest_os <- plotForest(readRDS(file.path(results_dir, \cox_OS_additive_terms_resection_lgg_group_cluster_CLK1_ex4_PSI.RDS\)))

forest_os

ggsave(file.path(plot_dir, \forest_add_OS_resection_lgg_group_cluster_assignment_CLK1_ex4_PSI.pdf\),
       forest_os,
       width = 10, height = 6, units = \in\,
       device = \pdf\)

add_model_efs <- fit_save_model(metadata[!metadata$extent_of_tumor_resection %in% c(\Not Reported\, \Unavailable\),],
                              terms = \extent_of_tumor_resection+lgg_group+cluster+age_at_diagnosis_years+CLK1_ex4_PSI\,
                               file.path(results_dir, \cox_EFS_additive_terms_resection_lgg_group_cluster_CLK1_ex4_PSI.RDS\),
                               \multivariate\,
                               years_col = \EFS_years\,
                               status_col = \EFS_status\)

forest_efs <- plotForest(readRDS(file.path(results_dir, \cox_EFS_additive_terms_resection_lgg_group_cluster_CLK1_ex4_PSI.RDS\)))

forest_efs

ggsave(file.path(plot_dir, \forest_add_EFS_resection_lgg_group_cluster_assignment_CLK1_ex4_PSI.pdf\),
       forest_efs,
       width = 10, height = 6, units = \in\,
       device = \pdf\)

Interaction with GSVA, SBI, CLK1

models <- c("spliceosome_gsva_score", "SBI", "CLK1_Ex4_TPM", "CLK1_ex4_PSI")
# by cluster
for (each in models) {
  int_model_efs <- fit_save_model(metadata[!metadata$extent_of_tumor_resection %in% c("Not Reported", "Unavailable"),],
                                terms = paste0("extent_of_tumor_resection+lgg_group+cluster*", each, "+age_at_diagnosis_years"),
                                 file.path(results_dir, paste0("cox_EFS_interaction_terms_resection_lgg_group_cluster_", each, ".RDS")),
                                 "multivariate",
                                 years_col = "EFS_years",
                                 status_col = "EFS_status")
  
  int_forest_efs <- plotForest(readRDS(file.path(results_dir, paste0("cox_EFS_interaction_terms_resection_lgg_group_cluster_", each, ".RDS"))))
  
  int_forest_efs
  
  ggsave(file.path(plot_dir, paste0("forest_int_EFS_resection_lgg_group_cluster_assignment_", each, ".pdf")),
         int_forest_efs,
         width = 10, height = 6, units = "in",
         device = "pdf")

  int_model_os <- fit_save_model(metadata[!metadata$extent_of_tumor_resection %in% c("Not Reported", "Unavailable"),],
                                terms = paste0("extent_of_tumor_resection+lgg_group+cluster*", each, "+age_at_diagnosis_years"),
                                 file.path(results_dir, paste0("cox_OS_interaction_terms_resection_lgg_group_cluster_", each, ".RDS")),
                                 "multivariate",
                                 years_col = "OS_years",
                                 status_col = "OS_status")
  
  int_forest_os <- plotForest(readRDS(file.path(results_dir, paste0("cox_OS_interaction_terms_resection_lgg_group_cluster_", each, ".RDS"))))
  
  int_forest_os
  
  ggsave(file.path(plot_dir, paste0("forest_int_OS_resection_lgg_group_cluster_assignment_", each, ".pdf")),
         int_forest_os,
         width = 10, height = 6, units = "in",
         device = "pdf")
}

## clk1 x age
  int_model_efs <- fit_save_model(metadata[!metadata$extent_of_tumor_resection %in% c("Not Reported", "Unavailable"),],
                                terms = paste0("extent_of_tumor_resection+lgg_group+cluster+CLK1_Ex4_TPM*age_at_diagnosis_years"),
                                 file.path(results_dir, paste0("cox_EFS_interaction_terms_resection_lgg_group_cluster_CLK1_Ex4_TPM_age.RDS")),
                                 "multivariate",
                                 years_col = "EFS_years",
                                 status_col = "EFS_status")
  
  int_forest_efs <- plotForest(readRDS(file.path(results_dir, paste0("cox_EFS_interaction_terms_resection_lgg_group_cluster_CLK1_Ex4_TPM_age.RDS"))))
  
  int_forest_efs
  
  ggsave(file.path(plot_dir, paste0("forest_int_EFS_resection_lgg_group_cluster_clk1_age.pdf")),
         int_forest_efs,
         width = 10, height = 6, units = "in",
         device = "pdf")

  int_model_os <- fit_save_model(metadata[!metadata$extent_of_tumor_resection %in% c("Not Reported", "Unavailable"),],
                                terms = paste0("extent_of_tumor_resection+lgg_group+cluster+CLK1_Ex4_TPM*age_at_diagnosis_years"),
                                 file.path(results_dir, paste0("cox_OS_interaction_terms_resection_lgg_group_cluster_clk1_age.RDS")),
                                 "multivariate",
                                 years_col = "OS_years",
                                 status_col = "OS_status")
  
  int_forest_os <- plotForest(readRDS(file.path(results_dir, paste0("cox_OS_interaction_terms_resection_lgg_group_cluster_clk1_age.RDS"))))
  
  int_forest_os
  
  ggsave(file.path(plot_dir, paste0("forest_int_OS_resection_lgg_group_cluster_clk1_age.pdf")),
         int_forest_os,
         width = 10, height = 6, units = "in",
         device = "pdf")

models2 <- c("SBI", "CLK1_Ex4_TPM", "CLK1_ex4_PSI")
for (each in models2) {
  #### by spliceosome_gsva_score
  int_model_efs <- fit_save_model(metadata[!metadata$extent_of_tumor_resection %in% c("Not Reported", "Unavailable"),],
                                terms = paste0("extent_of_tumor_resection+lgg_group+cluster+spliceosome_gsva_score*", each, "+age_at_diagnosis_years"),
                                 file.path(results_dir, paste0("cox_EFS_interaction_terms_resection_lgg_group_cluster_spliceosome_gsva_score_", each, ".RDS")),
                                 "multivariate",
                                 years_col = "EFS_years",
                                 status_col = "EFS_status")
  
  int_forest_efs <- plotForest(readRDS(file.path(results_dir, paste0("cox_EFS_interaction_terms_resection_lgg_group_cluster_spliceosome_gsva_score_", each, ".RDS"))))
  
  int_forest_efs
  
  ggsave(file.path(plot_dir, paste0("cox_EFS_interaction_terms_resection_lgg_group_cluster_spliceosome_gsva_score_", each, ".pdf")),
         int_forest_efs,
         width = 10, height = 6, units = "in",
         device = "pdf")
}
  


add_model_efs <- fit_save_model(metadata[!metadata$extent_of_tumor_resection %in% c("Not Reported", "Unavailable"),],
                              terms = "extent_of_tumor_resection+lgg_group+cluster+age_at_diagnosis_years+spliceosome_gsva_score+CLK1_Ex4_TPM",
                               file.path(results_dir, "cox_EFS_additive_terms_resection_lgg_group_cluster_spliceosome_score_CLK1_Ex4_TPM.RDS"),
                               "multivariate",
                               years_col = "EFS_years",
                               status_col = "EFS_status")

forest_efs <- plotForest(readRDS(file.path(results_dir, "cox_EFS_additive_terms_resection_lgg_group_cluster_spliceosome_score_CLK1_Ex4_TPM.RDS")))

forest_efs

ggsave(file.path(plot_dir, "forest_add_EFS_resection_lgg_group_cluster_assignment_spliceosome_score_CLK1_Ex4_TPM.pdf"),
       forest_efs,
       width = 10, height = 6, units = "in",
       device = "pdf")


add_model_os <- fit_save_model(metadata[!metadata$extent_of_tumor_resection %in% c("Not Reported", "Unavailable"),],
                              terms = "extent_of_tumor_resection+lgg_group+cluster+age_at_diagnosis_years+spliceosome_gsva_score+CLK1_Ex4_TPM",
                               file.path(results_dir, "cox_OS_additive_terms_resection_lgg_group_cluster_spliceosome_score_CLK1_Ex4_TPM.RDS"),
                               "multivariate",
                               years_col = "EFS_years",
                               status_col = "EFS_status")

forest_os <- plotForest(readRDS(file.path(results_dir, "cox_OS_additive_terms_resection_lgg_group_cluster_spliceosome_score_CLK1_Ex4_TPM.RDS")))

forest_os

ggsave(file.path(plot_dir, "forest_add_OS_resection_lgg_group_cluster_assignment_spliceosome_score_CLK1_Ex4_TPM.pdf"),
       forest_efs,
       width = 10, height = 6, units = "in",
       device = "pdf")

Filter for clusters

cluster_list <- unique(metadata$cluster)

for (each in cluster_list) {
cluster_df <- metadata %>%
  dplyr::filter(cluster == each,
                !is.na(EFS_days)) %>%
  dplyr::mutate(CLK1_TPM_group = case_when(
      CLK1_Ex4_TPM > summary(CLK1_Ex4_TPM)[\3rd Qu.\] ~ \High CLK1 TPM\,
      CLK1_Ex4_TPM < summary(CLK1_Ex4_TPM)[\1st Qu.\] ~ \Low CLK1 TPM\,
      TRUE ~ NA_character_),
      CLK1_PSI_group = case_when(CLK1_ex4_PSI > summary(CLK1_ex4_PSI)[\3rd Qu.\] ~ \High CLK1 PSI\,
      CLK1_ex4_PSI < summary(CLK1_ex4_PSI)[\1st Qu.\] ~ \Low CLK1 PSI\,
      TRUE ~ NA_character_
    )) %>%
  dplyr::mutate(CLK1_TPM_group = fct_relevel(CLK1_TPM_group,
                                                 c(\Low CLK1 TPM\, \High CLK1 TPM\)),
                CLK1_PSI_group = fct_relevel(CLK1_PSI_group,
                                                 c(\Low CLK1 PSI\, \High CLK1 PSI\))) %>%
 # collapse groups which do not have min N
   dplyr::mutate(
    plot_group = forcats::fct_drop(plot_group),
    plot_group = forcats::fct_lump_min(plot_group, min = 3, other_level = \Collapsed\)
  )

 safe_each <- gsub(\[^A-Za-z0-9_-]+\, \_\, each)

# Generate KM models with `CLK1_TPM_group` as covariate
# Generate kaplan meier survival models for OS and EFS, and save outputs
cluster_clk_tpm_kap_os <- survival_analysis(
  metadata  = cluster_df %>% 
    dplyr::filter(!is.na(CLK1_TPM_group)),
  ind_var = \CLK1_TPM_group\,
  test = \kap.meier\,
  metadata_sample_col = \Kids_First_Biospecimen_ID\,
  days_col = \OS_days\,
  status_col = \OS_status\
)

readr::write_rds(cluster_clk_tpm_kap_os,
                 file.path(results_dir, paste0( \logrank_\, safe_each, \_OS_clk1_tpm_group.RDS\)))

cluster_clk_tpm_kap_efs <- survival_analysis(
  metadata  = cluster_df %>% 
    dplyr::filter(!is.na(CLK1_TPM_group)),
  ind_var = \CLK1_TPM_group\,
  test = \kap.meier\,
  metadata_sample_col = \Kids_First_Biospecimen_ID\,
  days_col = \EFS_days\,
  status_col = \EFS_status\
)

readr::write_rds(cluster_clk_tpm_kap_efs,
                 file.path(results_dir, paste0( \logrank_\, safe_each, \_EFS_clk1_tpm_group.RDS\)))

# Generate KM models with `CLK1_PSI_group` as covariate
# Generate kaplan meier survival models for OS and EFS, and save outputs
cluster_clk_psi_kap_os <- survival_analysis(
  metadata  = cluster_df %>% 
    dplyr::filter(!is.na(CLK1_PSI_group)),
  ind_var = \CLK1_PSI_group\,
  test = \kap.meier\,
  metadata_sample_col = \Kids_First_Biospecimen_ID\,
  days_col = \OS_days\,
  status_col = \OS_status\
)

readr::write_rds(cluster_clk_psi_kap_os,
                 file.path(results_dir, paste0( \logrank_\, safe_each, \_OS_clk1_psi_group.RDS\)))

cluster_clk_psi_kap_efs <- survival_analysis(
  metadata  = cluster_df %>% 
    dplyr::filter(!is.na(CLK1_PSI_group)),
  ind_var = \CLK1_PSI_group\,
  test = \kap.meier\,
  metadata_sample_col = \Kids_First_Biospecimen_ID\,
  days_col = \EFS_days\,
  status_col = \EFS_status\
)

readr::write_rds(cluster_clk_psi_kap_efs,
                 file.path(results_dir, paste0( \logrank_\, safe_each, \_EFS_clk1_psi_group.RDS\)))

# Generate cluster KM SI_group plots

km_cluster_clk_tpm_os_plot <- plotKM(model = cluster_clk_tpm_kap_os,
                    variable = \CLK1_TPM_group\,
                    combined = F, 
                    title = paste0(each, \

LS0tCnRpdGxlOiAiUnVuIHNwbGljaW5nIGNsdXN0ZXIgYXNzaWdubWVudCwgc3BsaWNpbmcgYnVyZGVuLCBnc3ZhLCBDTEsxIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IFRSVUUKICAgIHRvY19mbG9hdDogVFJVRQphdXRob3I6IFJ5YW4gQ29yYmV0dCwgYWRhcHRlZCBieSBKbyBMeW5uZSBSb2tpdGEgZm9yIENMSzEKZGF0ZTogMjAyNApwYXJhbXM6CiAgcGxvdF9jaTogVFJVRQotLS0KCioqUHVycG9zZToqKiAKClJ1bnMgc3Vydml2YWwgYW5hbHlzaXMgbW9kZWxzIHVzaW5nIHNwbGljaW5nIGNsdXN0ZXIgYXNzaWdubWVudCBhbmQgMSkgc2luZ2xlIGV4b24gc3BsaWNpbmcgYnVyZGVuIGluZGV4IChTQkkpIDIpIEtFR0cgU3BsaWNlb3NvbWUgR1NWQSBzY29yZXMgb3IgMykgQ0xLMSBleG9uIDQgVFBNIGFzIGEgcHJlZGljdG9yCgojIyBVc2FnZSAKClVzZXMgYSB3cmFwcGVyIGZ1bmN0aW9uIChgc3Vydml2YWxfYW5hbHlzaXNgKSBmcm9tIHV0aWxzIGZvbGRlci4gCgojIyBTZXR1cAoKIyMjIyBQYWNrYWdlcyBhbmQgZnVuY3Rpb25zCgpMb2FkIHBhY2thZ2VzLCBzZXQgZGlyZWN0b3J5IHBhdGhzIGFuZCBjYWxsIHNldHVwIHNjcmlwdAoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHN1cnZpdmFsKQpsaWJyYXJ5KGdncHVicikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHBhdGNod29yaykKCnJvb3RfZGlyIDwtIHJwcm9qcm9vdDo6ZmluZF9yb290KHJwcm9qcm9vdDo6aGFzX2RpcigiLmdpdCIpKQoKZGF0YV9kaXIgPC0gZmlsZS5wYXRoKHJvb3RfZGlyLCAiZGF0YSIpCmFuYWx5c2lzX2RpciA8LSBmaWxlLnBhdGgocm9vdF9kaXIsICJhbmFseXNlcyIsICJzdXJ2aXZhbCIpCmlucHV0X2RpciA8LSBmaWxlLnBhdGgoYW5hbHlzaXNfZGlyLCAicmVzdWx0cyIpCnJlc3VsdHNfZGlyIDwtIGZpbGUucGF0aChhbmFseXNpc19kaXIsICJyZXN1bHRzIikKcGxvdF9kaXIgPC0gZmlsZS5wYXRoKGFuYWx5c2lzX2RpciwgInBsb3RzIikKCiMgSWYgdGhlIGlucHV0IGFuZCByZXN1bHRzIGRpcmVjdG9yaWVzIGRvIG5vdCBleGlzdCwgY3JlYXRlIGl0CmlmICghZGlyLmV4aXN0cyhyZXN1bHRzX2RpcikpIHsKICBkaXIuY3JlYXRlKHJlc3VsdHNfZGlyLCByZWN1cnNpdmUgPSBUUlVFKQp9Cgpzb3VyY2UoZmlsZS5wYXRoKGFuYWx5c2lzX2RpciwgInV0aWwiLCAic3Vydml2YWxfbW9kZWxzLlIiKSkKa25pdHI6Om9wdHNfY2h1bmskc2V0KGNhY2hlID0gRkFMU0UpCmBgYAoKU2V0IG1ldGFkYXRhIGFuZCBjbHVzdGVyIGFzc2lnbm1lbnQgZmlsZSBwYXRocwoKYGBge3Igc2V0IHBhdGhzfQptZXRhZGF0YV9maWxlIDwtIGZpbGUucGF0aChpbnB1dF9kaXIsICJzcGxpY2luZ19pbmRpY2VzX3dpdGhfc3Vydml2YWwudHN2IikKCmNsdXN0ZXJfZmlsZSA8LSBmaWxlLnBhdGgocm9vdF9kaXIsICJhbmFseXNlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgInNhbXBsZS1wc2ktY2x1c3RlcmluZyIsICJyZXN1bHRzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAic2FtcGxlLWNsdXN0ZXItbWV0YWRhdGEtdG9wLTUwMDAtZXZlbnRzLXN0cmFuZGVkLnRzdiIpCgprZWdnX3Njb3Jlc19zdHJhbmRlZF9maWxlIDwtIGZpbGUucGF0aChyb290X2RpciwgImFuYWx5c2VzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAic2FtcGxlLXBzaS1jbHVzdGVyaW5nIiwgInJlc3VsdHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICJnc3ZhX291dHB1dF9zdHJhbmRlZC50c3YiKQoKdHBtX2ZpbGUgPC0gZmlsZS5wYXRoKGRhdGFfZGlyLCAicm5hLWlzb2Zvcm0tZXhwcmVzc2lvbi1yc2VtLXRwbS5yZHMiKQpjbGsxX3BzaV9maWxlIDwtIGZpbGUucGF0aChyb290X2RpciwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJhbmFseXNlcyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAiQ0xLMS1zcGxpY2luZ19jb3JyZWxhdGlvbnMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgInJlc3VsdHMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgImNsazEtZXhvbjQtcHNpLnRzdiIpCmBgYAoKV3JhbmdsZSBkYXRhIApBZGQgY2x1c3RlciBhc3NpZ25tZW50IGFuZCBzcGxpY2Vvc29tZSBnc3ZhIHNjb3JlcyB0byBgbWV0YWRhdGFgIGFuZCBkZWZpbmUgY29sdW1uIGBsZ2dfZ3JvdXBgIChMR0cgb3Igbm9uX0xHRykKCmBgYHtyfQptZXRhZGF0YSA8LSByZWFkX3RzdihtZXRhZGF0YV9maWxlKQoKY2x1c3RlcnMgPC0gcmVhZF90c3YoY2x1c3Rlcl9maWxlKSAlPiUKICBkcGx5cjo6cmVuYW1lKEtpZHNfRmlyc3RfQmlvc3BlY2ltZW5fSUQgPSBzYW1wbGVfaWQpCgpjbGsxX3BzaSA8LSByZWFkX3RzdihjbGsxX3BzaV9maWxlKSAlPiUKICBkcGx5cjo6cmVuYW1lKENMSzFfZXg0X1BTSSA9IFBTSSkgJT4lCiAgc2VsZWN0KC1wbG90X2dyb3VwKQoKZ3N2YV9zY29yZXMgPC0gcmVhZF90c3Yoa2VnZ19zY29yZXNfc3RyYW5kZWRfZmlsZSkgJT4lCiAgZHBseXI6OmZpbHRlcihnZW5lc2V0ID09ICJLRUdHX1NQTElDRU9TT01FIikgJT4lCiAgZHBseXI6OnJlbmFtZShzcGxpY2Vvc29tZV9nc3ZhX3Njb3JlID0gc2NvcmUpCgphbGxfY2xrNF90cmFuc2NyX2NvdW50cyA8LSByZWFkUkRTKHRwbV9maWxlKSAlPiUKICBmaWx0ZXIoZ3JlcGwoIl5DTEsxIiwgZ2VuZV9zeW1ib2wpKSAlPiUKICBtdXRhdGUoCiAgICB0cmFuc2NyaXB0X2lkID0gY2FzZV93aGVuKAogICAgICB0cmFuc2NyaXB0X2lkICVpbiUgYygiRU5TVDAwMDAwMzIxMzU2LjkiLCAiRU5TVDAwMDAwNDM0ODEzLjMiLCAiRU5TVDAwMDAwNDA5NDAzLjYiKSB+ICJFeG9uIDQiLAogICAgICAjIHRyYW5zY3JpcHRfaWQgPT0gIkVOU1QwMDAwMDMyMTM1Ni45IiB+ICJFeG9uIDQiLAogICAgICBUUlVFIH4gIk90aGVyIgogICAgKQogICkgJT4lCiAgZ3JvdXBfYnkodHJhbnNjcmlwdF9pZCkgJT4lCiAgc3VtbWFyaXNlKGFjcm9zcyhzdGFydHNfd2l0aCgiQlMiKSwgc3VtLCBuYS5ybSA9IFRSVUUpKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IC10cmFuc2NyaXB0X2lkLCBuYW1lc190byA9ICJLaWRzX0ZpcnN0X0Jpb3NwZWNpbWVuX0lEIiwgdmFsdWVzX3RvID0gIkNMSzFfRXg0X1RQTSIpICU+JQogIGZpbHRlcih0cmFuc2NyaXB0X2lkID09ICJFeG9uIDQiKSAlPiUKICBpbm5lcl9qb2luKGNsdXN0ZXJzLCBieSA9ICJLaWRzX0ZpcnN0X0Jpb3NwZWNpbWVuX0lEIikgJT4lCiAgbGVmdF9qb2luKGNsazFfcHNpKQoKIyBob3cgbWFueSBjbHVzdGVycz8Kbl9jbHVzdCA8LSBsZW5ndGgodW5pcXVlKGNsdXN0ZXJzJGNsdXN0ZXIpKQoKbWV0YWRhdGEgPC0gbWV0YWRhdGEgJT4lCiAgcmlnaHRfam9pbihhbGxfY2xrNF90cmFuc2NyX2NvdW50cyAlPiUgZHBseXI6OnNlbGVjdChLaWRzX0ZpcnN0X0Jpb3NwZWNpbWVuX0lELAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyLCBDTEsxX0V4NF9UUE0sIENMSzFfZXg0X1BTSSkpICU+JQogIGxlZnRfam9pbihnc3ZhX3Njb3JlcyAlPiUgZHBseXI6OnNlbGVjdChzYW1wbGVfaWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwbGljZW9zb21lX2dzdmFfc2NvcmUpLAogICAgICAgICAgICBieSA9IGMoIktpZHNfRmlyc3RfQmlvc3BlY2ltZW5fSUQiID0gInNhbXBsZV9pZCIpKSAlPiUgCiAgZHBseXI6Om11dGF0ZShjbHVzdGVyID0gZ2x1ZTo6Z2x1ZSgiQ2x1c3RlciB7Y2x1c3Rlcn0iKSkgJT4lCiAgZHBseXI6Om11dGF0ZShjbHVzdGVyID0gZmN0X3JlbGV2ZWwoY2x1c3RlciwgcGFzdGUwKCJDbHVzdGVyICIsIDE6bl9jbHVzdCkpKSAlPiUKICBkcGx5cjo6bXV0YXRlKGxnZ19ncm91cCA9IGNhc2Vfd2hlbigKICAgIHBsb3RfZ3JvdXAgPT0gIkxvdy1ncmFkZSBnbGlvbWEiIH4gIkxHRyIsCiAgICBUUlVFIH4gIm5vbi1MR0ciCiAgKSkgJT4lCiAgZHBseXI6Om11dGF0ZShTQkkgPSBTSV9Ub3RhbCAqIDEwKSAlPiUKICBkcGx5cjo6bXV0YXRlKGFnZV9hdF9kaWFnbm9zaXNfeWVhcnMgPSBhZ2VfYXRfZGlhZ25vc2lzX2RheXMvMzY1LjI1KQpgYGAKCkdlbmVyYXRlIGNveHBoIG1vZGVscyBpbmNsdWRpbmcgZXh0ZW50IG9mIHR1bW9yIHJlc2VjdGlvbiwgbGdnIGdyb3VwLCBjbHVzdGVyIGFzc2lnbm1lbnQsIFNCSSwgYW5kIENMSzEgZXhvbiA0IFRQTSBhcyBjb3ZhcmlhdGVzCgpgYGB7cn0KYWRkX21vZGVsX29zIDwtIGZpdF9zYXZlX21vZGVsKG1ldGFkYXRhWyFtZXRhZGF0YSRleHRlbnRfb2ZfdHVtb3JfcmVzZWN0aW9uICVpbiUgYygiTm90IFJlcG9ydGVkIiwgIlVuYXZhaWxhYmxlIiksXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVybXMgPSAiZXh0ZW50X29mX3R1bW9yX3Jlc2VjdGlvbitsZ2dfZ3JvdXArY2x1c3RlcithZ2VfYXRfZGlhZ25vc2lzX3llYXJzK1NCSStDTEsxX0V4NF9UUE0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZS5wYXRoKHJlc3VsdHNfZGlyLCAiY294X09TX2FkZGl0aXZlX3Rlcm1zX3Jlc2VjdGlvbl9sZ2dfZ3JvdXBfY2x1c3Rlcl9TQklfQ0xLMV9FeDRfVFBNLlJEUyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm11bHRpdmFyaWF0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyc19jb2wgPSAiT1NfeWVhcnMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHVzX2NvbCA9ICJPU19zdGF0dXMiKQoKZm9yZXN0X29zIDwtIHBsb3RGb3Jlc3QocmVhZFJEUyhmaWxlLnBhdGgocmVzdWx0c19kaXIsICJjb3hfT1NfYWRkaXRpdmVfdGVybXNfcmVzZWN0aW9uX2xnZ19ncm91cF9jbHVzdGVyX1NCSV9DTEsxX0V4NF9UUE0uUkRTIikpKQoKZm9yZXN0X29zCgpnZ3NhdmUoZmlsZS5wYXRoKHBsb3RfZGlyLCAiZm9yZXN0X2FkZF9PU19yZXNlY3Rpb25fbGdnX2dyb3VwX2NsdXN0ZXJfYXNzaWdubWVudF9TQklfQ0xLMV9FeDRfVFBNLnBkZiIpLAogICAgICAgZm9yZXN0X29zLAogICAgICAgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNiwgdW5pdHMgPSAiaW4iLAogICAgICAgZGV2aWNlID0gInBkZiIpCgphZGRfbW9kZWxfZWZzIDwtIGZpdF9zYXZlX21vZGVsKG1ldGFkYXRhWyFtZXRhZGF0YSRleHRlbnRfb2ZfdHVtb3JfcmVzZWN0aW9uICVpbiUgYygiTm90IFJlcG9ydGVkIiwgIlVuYXZhaWxhYmxlIiksXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVybXMgPSAiZXh0ZW50X29mX3R1bW9yX3Jlc2VjdGlvbitsZ2dfZ3JvdXArY2x1c3RlcithZ2VfYXRfZGlhZ25vc2lzX3llYXJzK1NCSStDTEsxX0V4NF9UUE0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZS5wYXRoKHJlc3VsdHNfZGlyLCAiY294X0VGU19hZGRpdGl2ZV90ZXJtc19yZXNlY3Rpb25fbGdnX2dyb3VwX2NsdXN0ZXJfU0JJX0NMSzFfRXg0X1RQTS5SRFMiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJtdWx0aXZhcmlhdGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhcnNfY29sID0gIkVGU195ZWFycyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0dXNfY29sID0gIkVGU19zdGF0dXMiKQoKZm9yZXN0X2VmcyA8LSBwbG90Rm9yZXN0KHJlYWRSRFMoZmlsZS5wYXRoKHJlc3VsdHNfZGlyLCAiY294X0VGU19hZGRpdGl2ZV90ZXJtc19yZXNlY3Rpb25fbGdnX2dyb3VwX2NsdXN0ZXJfU0JJX0NMSzFfRXg0X1RQTS5SRFMiKSkpCgpmb3Jlc3RfZWZzCgpnZ3NhdmUoZmlsZS5wYXRoKHBsb3RfZGlyLCAiZm9yZXN0X2FkZF9FRlNfcmVzZWN0aW9uX2xnZ19ncm91cF9jbHVzdGVyX2Fzc2lnbm1lbnRfU0JJX0NMSzFfRXg0X1RQTS5wZGYiKSwKICAgICAgIGZvcmVzdF9lZnMsCiAgICAgICB3aWR0aCA9IDEwLCBoZWlnaHQgPSA2LCB1bml0cyA9ICJpbiIsCiAgICAgICBkZXZpY2UgPSAicGRmIikKYGBgCnJlcGVhdCBhbmFseXNpcyB3aXRoIENMSzEgZXhvbiA0IFRQTSBhbG9uZQoKYGBge3J9CmFkZF9tb2RlbF9vcyA8LSBmaXRfc2F2ZV9tb2RlbChtZXRhZGF0YVshbWV0YWRhdGEkZXh0ZW50X29mX3R1bW9yX3Jlc2VjdGlvbiAlaW4lIGMoIk5vdCBSZXBvcnRlZCIsICJVbmF2YWlsYWJsZSIpLF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlcm1zID0gImV4dGVudF9vZl90dW1vcl9yZXNlY3Rpb24rbGdnX2dyb3VwK2NsdXN0ZXIrYWdlX2F0X2RpYWdub3Npc195ZWFycytDTEsxX0V4NF9UUE0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZS5wYXRoKHJlc3VsdHNfZGlyLCAiY294X09TX2FkZGl0aXZlX3Rlcm1zX3Jlc2VjdGlvbl9sZ2dfZ3JvdXBfY2x1c3Rlcl9DTEsxX0V4NF9UUE0uUkRTIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibXVsdGl2YXJpYXRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXJzX2NvbCA9ICJPU195ZWFycyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0dXNfY29sID0gIk9TX3N0YXR1cyIpCgpmb3Jlc3Rfb3MgPC0gcGxvdEZvcmVzdChyZWFkUkRTKGZpbGUucGF0aChyZXN1bHRzX2RpciwgImNveF9PU19hZGRpdGl2ZV90ZXJtc19yZXNlY3Rpb25fbGdnX2dyb3VwX2NsdXN0ZXJfQ0xLMV9FeDRfVFBNLlJEUyIpKSkKCmZvcmVzdF9vcwoKZ2dzYXZlKGZpbGUucGF0aChwbG90X2RpciwgImZvcmVzdF9hZGRfT1NfcmVzZWN0aW9uX2xnZ19ncm91cF9jbHVzdGVyX2Fzc2lnbm1lbnRfQ0xLMV9FeDRfVFBNLnBkZiIpLAogICAgICAgZm9yZXN0X29zLAogICAgICAgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNiwgdW5pdHMgPSAiaW4iLAogICAgICAgZGV2aWNlID0gInBkZiIpCgoKYWRkX21vZGVsX2VmcyA8LSBmaXRfc2F2ZV9tb2RlbChtZXRhZGF0YVshbWV0YWRhdGEkZXh0ZW50X29mX3R1bW9yX3Jlc2VjdGlvbiAlaW4lIGMoIk5vdCBSZXBvcnRlZCIsICJVbmF2YWlsYWJsZSIpLF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlcm1zID0gImV4dGVudF9vZl90dW1vcl9yZXNlY3Rpb24rbGdnX2dyb3VwK2NsdXN0ZXIrYWdlX2F0X2RpYWdub3Npc195ZWFycytDTEsxX0V4NF9UUE0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZS5wYXRoKHJlc3VsdHNfZGlyLCAiY294X0VGU19hZGRpdGl2ZV90ZXJtc19yZXNlY3Rpb25fbGdnX2dyb3VwX2NsdXN0ZXJfQ0xLMV9FeDRfVFBNLlJEUyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm11bHRpdmFyaWF0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyc19jb2wgPSAiRUZTX3llYXJzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXR1c19jb2wgPSAiRUZTX3N0YXR1cyIpCgpmb3Jlc3RfZWZzIDwtIHBsb3RGb3Jlc3QocmVhZFJEUyhmaWxlLnBhdGgocmVzdWx0c19kaXIsICJjb3hfRUZTX2FkZGl0aXZlX3Rlcm1zX3Jlc2VjdGlvbl9sZ2dfZ3JvdXBfY2x1c3Rlcl9DTEsxX0V4NF9UUE0uUkRTIikpKQoKZm9yZXN0X2VmcwoKZ2dzYXZlKGZpbGUucGF0aChwbG90X2RpciwgImZvcmVzdF9hZGRfRUZTX3Jlc2VjdGlvbl9sZ2dfZ3JvdXBfY2x1c3Rlcl9hc3NpZ25tZW50X0NMSzFfRXg0X1RQTS5wZGYiKSwKICAgICAgIGZvcmVzdF9lZnMsCiAgICAgICB3aWR0aCA9IDEwLCBoZWlnaHQgPSA2LCB1bml0cyA9ICJpbiIsCiAgICAgICBkZXZpY2UgPSAicGRmIikKCgpgYGAKCgpyZXBlYXQgYW5hbHlzaXMgd2l0aCBDTEsxIGV4b24gNCBQU0kKCmBgYHtyfQphZGRfbW9kZWxfb3MgPC0gZml0X3NhdmVfbW9kZWwobWV0YWRhdGFbIW1ldGFkYXRhJGV4dGVudF9vZl90dW1vcl9yZXNlY3Rpb24gJWluJSBjKCJOb3QgUmVwb3J0ZWQiLCAiVW5hdmFpbGFibGUiKSxdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXJtcyA9ICJleHRlbnRfb2ZfdHVtb3JfcmVzZWN0aW9uK2xnZ19ncm91cCtjbHVzdGVyK2FnZV9hdF9kaWFnbm9zaXNfeWVhcnMrQ0xLMV9leDRfUFNJIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGUucGF0aChyZXN1bHRzX2RpciwgImNveF9PU19hZGRpdGl2ZV90ZXJtc19yZXNlY3Rpb25fbGdnX2dyb3VwX2NsdXN0ZXJfQ0xLMV9leDRfUFNJLlJEUyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm11bHRpdmFyaWF0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyc19jb2wgPSAiT1NfeWVhcnMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHVzX2NvbCA9ICJPU19zdGF0dXMiKQoKZm9yZXN0X29zIDwtIHBsb3RGb3Jlc3QocmVhZFJEUyhmaWxlLnBhdGgocmVzdWx0c19kaXIsICJjb3hfT1NfYWRkaXRpdmVfdGVybXNfcmVzZWN0aW9uX2xnZ19ncm91cF9jbHVzdGVyX0NMSzFfZXg0X1BTSS5SRFMiKSkpCgpmb3Jlc3Rfb3MKCmdnc2F2ZShmaWxlLnBhdGgocGxvdF9kaXIsICJmb3Jlc3RfYWRkX09TX3Jlc2VjdGlvbl9sZ2dfZ3JvdXBfY2x1c3Rlcl9hc3NpZ25tZW50X0NMSzFfZXg0X1BTSS5wZGYiKSwKICAgICAgIGZvcmVzdF9vcywKICAgICAgIHdpZHRoID0gMTAsIGhlaWdodCA9IDYsIHVuaXRzID0gImluIiwKICAgICAgIGRldmljZSA9ICJwZGYiKQoKYWRkX21vZGVsX2VmcyA8LSBmaXRfc2F2ZV9tb2RlbChtZXRhZGF0YVshbWV0YWRhdGEkZXh0ZW50X29mX3R1bW9yX3Jlc2VjdGlvbiAlaW4lIGMoIk5vdCBSZXBvcnRlZCIsICJVbmF2YWlsYWJsZSIpLF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlcm1zID0gImV4dGVudF9vZl90dW1vcl9yZXNlY3Rpb24rbGdnX2dyb3VwK2NsdXN0ZXIrYWdlX2F0X2RpYWdub3Npc195ZWFycytDTEsxX2V4NF9QU0kiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZS5wYXRoKHJlc3VsdHNfZGlyLCAiY294X0VGU19hZGRpdGl2ZV90ZXJtc19yZXNlY3Rpb25fbGdnX2dyb3VwX2NsdXN0ZXJfQ0xLMV9leDRfUFNJLlJEUyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm11bHRpdmFyaWF0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyc19jb2wgPSAiRUZTX3llYXJzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXR1c19jb2wgPSAiRUZTX3N0YXR1cyIpCgpmb3Jlc3RfZWZzIDwtIHBsb3RGb3Jlc3QocmVhZFJEUyhmaWxlLnBhdGgocmVzdWx0c19kaXIsICJjb3hfRUZTX2FkZGl0aXZlX3Rlcm1zX3Jlc2VjdGlvbl9sZ2dfZ3JvdXBfY2x1c3Rlcl9DTEsxX2V4NF9QU0kuUkRTIikpKQoKZm9yZXN0X2VmcwoKZ2dzYXZlKGZpbGUucGF0aChwbG90X2RpciwgImZvcmVzdF9hZGRfRUZTX3Jlc2VjdGlvbl9sZ2dfZ3JvdXBfY2x1c3Rlcl9hc3NpZ25tZW50X0NMSzFfZXg0X1BTSS5wZGYiKSwKICAgICAgIGZvcmVzdF9lZnMsCiAgICAgICB3aWR0aCA9IDEwLCBoZWlnaHQgPSA2LCB1bml0cyA9ICJpbiIsCiAgICAgICBkZXZpY2UgPSAicGRmIikKYGBgCgoKSW50ZXJhY3Rpb24gd2l0aCBHU1ZBLCBTQkksIENMSzEKCmBgYHtyIEludGVyYWN0aW9uIG1vZGVscyB3aXRoIEdTVkEsIFNCSSwgQ0xLMX0KbW9kZWxzIDwtIGMoInNwbGljZW9zb21lX2dzdmFfc2NvcmUiLCAiU0JJIiwgIkNMSzFfRXg0X1RQTSIsICJDTEsxX2V4NF9QU0kiKQojIGJ5IGNsdXN0ZXIKZm9yIChlYWNoIGluIG1vZGVscykgewogIGludF9tb2RlbF9lZnMgPC0gZml0X3NhdmVfbW9kZWwobWV0YWRhdGFbIW1ldGFkYXRhJGV4dGVudF9vZl90dW1vcl9yZXNlY3Rpb24gJWluJSBjKCJOb3QgUmVwb3J0ZWQiLCAiVW5hdmFpbGFibGUiKSxdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlcm1zID0gcGFzdGUwKCJleHRlbnRfb2ZfdHVtb3JfcmVzZWN0aW9uK2xnZ19ncm91cCtjbHVzdGVyKiIsIGVhY2gsICIrYWdlX2F0X2RpYWdub3Npc195ZWFycyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlLnBhdGgocmVzdWx0c19kaXIsIHBhc3RlMCgiY294X0VGU19pbnRlcmFjdGlvbl90ZXJtc19yZXNlY3Rpb25fbGdnX2dyb3VwX2NsdXN0ZXJfIiwgZWFjaCwgIi5SRFMiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJtdWx0aXZhcmlhdGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyc19jb2wgPSAiRUZTX3llYXJzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHVzX2NvbCA9ICJFRlNfc3RhdHVzIikKICAKICBpbnRfZm9yZXN0X2VmcyA8LSBwbG90Rm9yZXN0KHJlYWRSRFMoZmlsZS5wYXRoKHJlc3VsdHNfZGlyLCBwYXN0ZTAoImNveF9FRlNfaW50ZXJhY3Rpb25fdGVybXNfcmVzZWN0aW9uX2xnZ19ncm91cF9jbHVzdGVyXyIsIGVhY2gsICIuUkRTIikpKSkKICAKICBpbnRfZm9yZXN0X2VmcwogIAogIGdnc2F2ZShmaWxlLnBhdGgocGxvdF9kaXIsIHBhc3RlMCgiZm9yZXN0X2ludF9FRlNfcmVzZWN0aW9uX2xnZ19ncm91cF9jbHVzdGVyX2Fzc2lnbm1lbnRfIiwgZWFjaCwgIi5wZGYiKSksCiAgICAgICAgIGludF9mb3Jlc3RfZWZzLAogICAgICAgICB3aWR0aCA9IDEwLCBoZWlnaHQgPSA2LCB1bml0cyA9ICJpbiIsCiAgICAgICAgIGRldmljZSA9ICJwZGYiKQoKICBpbnRfbW9kZWxfb3MgPC0gZml0X3NhdmVfbW9kZWwobWV0YWRhdGFbIW1ldGFkYXRhJGV4dGVudF9vZl90dW1vcl9yZXNlY3Rpb24gJWluJSBjKCJOb3QgUmVwb3J0ZWQiLCAiVW5hdmFpbGFibGUiKSxdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlcm1zID0gcGFzdGUwKCJleHRlbnRfb2ZfdHVtb3JfcmVzZWN0aW9uK2xnZ19ncm91cCtjbHVzdGVyKiIsIGVhY2gsICIrYWdlX2F0X2RpYWdub3Npc195ZWFycyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlLnBhdGgocmVzdWx0c19kaXIsIHBhc3RlMCgiY294X09TX2ludGVyYWN0aW9uX3Rlcm1zX3Jlc2VjdGlvbl9sZ2dfZ3JvdXBfY2x1c3Rlcl8iLCBlYWNoLCAiLlJEUyIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm11bHRpdmFyaWF0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXJzX2NvbCA9ICJPU195ZWFycyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXR1c19jb2wgPSAiT1Nfc3RhdHVzIikKICAKICBpbnRfZm9yZXN0X29zIDwtIHBsb3RGb3Jlc3QocmVhZFJEUyhmaWxlLnBhdGgocmVzdWx0c19kaXIsIHBhc3RlMCgiY294X09TX2ludGVyYWN0aW9uX3Rlcm1zX3Jlc2VjdGlvbl9sZ2dfZ3JvdXBfY2x1c3Rlcl8iLCBlYWNoLCAiLlJEUyIpKSkpCiAgCiAgaW50X2ZvcmVzdF9vcwogIAogIGdnc2F2ZShmaWxlLnBhdGgocGxvdF9kaXIsIHBhc3RlMCgiZm9yZXN0X2ludF9PU19yZXNlY3Rpb25fbGdnX2dyb3VwX2NsdXN0ZXJfYXNzaWdubWVudF8iLCBlYWNoLCAiLnBkZiIpKSwKICAgICAgICAgaW50X2ZvcmVzdF9vcywKICAgICAgICAgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNiwgdW5pdHMgPSAiaW4iLAogICAgICAgICBkZXZpY2UgPSAicGRmIikKfQoKIyMgY2xrMSB4IGFnZQogIGludF9tb2RlbF9lZnMgPC0gZml0X3NhdmVfbW9kZWwobWV0YWRhdGFbIW1ldGFkYXRhJGV4dGVudF9vZl90dW1vcl9yZXNlY3Rpb24gJWluJSBjKCJOb3QgUmVwb3J0ZWQiLCAiVW5hdmFpbGFibGUiKSxdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlcm1zID0gcGFzdGUwKCJleHRlbnRfb2ZfdHVtb3JfcmVzZWN0aW9uK2xnZ19ncm91cCtjbHVzdGVyK0NMSzFfRXg0X1RQTSphZ2VfYXRfZGlhZ25vc2lzX3llYXJzIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGUucGF0aChyZXN1bHRzX2RpciwgcGFzdGUwKCJjb3hfRUZTX2ludGVyYWN0aW9uX3Rlcm1zX3Jlc2VjdGlvbl9sZ2dfZ3JvdXBfY2x1c3Rlcl9DTEsxX0V4NF9UUE1fYWdlLlJEUyIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm11bHRpdmFyaWF0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXJzX2NvbCA9ICJFRlNfeWVhcnMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0dXNfY29sID0gIkVGU19zdGF0dXMiKQogIAogIGludF9mb3Jlc3RfZWZzIDwtIHBsb3RGb3Jlc3QocmVhZFJEUyhmaWxlLnBhdGgocmVzdWx0c19kaXIsIHBhc3RlMCgiY294X0VGU19pbnRlcmFjdGlvbl90ZXJtc19yZXNlY3Rpb25fbGdnX2dyb3VwX2NsdXN0ZXJfQ0xLMV9FeDRfVFBNX2FnZS5SRFMiKSkpKQogIAogIGludF9mb3Jlc3RfZWZzCiAgCiAgZ2dzYXZlKGZpbGUucGF0aChwbG90X2RpciwgcGFzdGUwKCJmb3Jlc3RfaW50X0VGU19yZXNlY3Rpb25fbGdnX2dyb3VwX2NsdXN0ZXJfY2xrMV9hZ2UucGRmIikpLAogICAgICAgICBpbnRfZm9yZXN0X2VmcywKICAgICAgICAgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNiwgdW5pdHMgPSAiaW4iLAogICAgICAgICBkZXZpY2UgPSAicGRmIikKCiAgaW50X21vZGVsX29zIDwtIGZpdF9zYXZlX21vZGVsKG1ldGFkYXRhWyFtZXRhZGF0YSRleHRlbnRfb2ZfdHVtb3JfcmVzZWN0aW9uICVpbiUgYygiTm90IFJlcG9ydGVkIiwgIlVuYXZhaWxhYmxlIiksXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXJtcyA9IHBhc3RlMCgiZXh0ZW50X29mX3R1bW9yX3Jlc2VjdGlvbitsZ2dfZ3JvdXArY2x1c3RlcitDTEsxX0V4NF9UUE0qYWdlX2F0X2RpYWdub3Npc195ZWFycyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlLnBhdGgocmVzdWx0c19kaXIsIHBhc3RlMCgiY294X09TX2ludGVyYWN0aW9uX3Rlcm1zX3Jlc2VjdGlvbl9sZ2dfZ3JvdXBfY2x1c3Rlcl9jbGsxX2FnZS5SRFMiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJtdWx0aXZhcmlhdGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyc19jb2wgPSAiT1NfeWVhcnMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0dXNfY29sID0gIk9TX3N0YXR1cyIpCiAgCiAgaW50X2ZvcmVzdF9vcyA8LSBwbG90Rm9yZXN0KHJlYWRSRFMoZmlsZS5wYXRoKHJlc3VsdHNfZGlyLCBwYXN0ZTAoImNveF9PU19pbnRlcmFjdGlvbl90ZXJtc19yZXNlY3Rpb25fbGdnX2dyb3VwX2NsdXN0ZXJfY2xrMV9hZ2UuUkRTIikpKSkKICAKICBpbnRfZm9yZXN0X29zCiAgCiAgZ2dzYXZlKGZpbGUucGF0aChwbG90X2RpciwgcGFzdGUwKCJmb3Jlc3RfaW50X09TX3Jlc2VjdGlvbl9sZ2dfZ3JvdXBfY2x1c3Rlcl9jbGsxX2FnZS5wZGYiKSksCiAgICAgICAgIGludF9mb3Jlc3Rfb3MsCiAgICAgICAgIHdpZHRoID0gMTAsIGhlaWdodCA9IDYsIHVuaXRzID0gImluIiwKICAgICAgICAgZGV2aWNlID0gInBkZiIpCgptb2RlbHMyIDwtIGMoIlNCSSIsICJDTEsxX0V4NF9UUE0iLCAiQ0xLMV9leDRfUFNJIikKZm9yIChlYWNoIGluIG1vZGVsczIpIHsKICAjIyMjIGJ5IHNwbGljZW9zb21lX2dzdmFfc2NvcmUKICBpbnRfbW9kZWxfZWZzIDwtIGZpdF9zYXZlX21vZGVsKG1ldGFkYXRhWyFtZXRhZGF0YSRleHRlbnRfb2ZfdHVtb3JfcmVzZWN0aW9uICVpbiUgYygiTm90IFJlcG9ydGVkIiwgIlVuYXZhaWxhYmxlIiksXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXJtcyA9IHBhc3RlMCgiZXh0ZW50X29mX3R1bW9yX3Jlc2VjdGlvbitsZ2dfZ3JvdXArY2x1c3RlcitzcGxpY2Vvc29tZV9nc3ZhX3Njb3JlKiIsIGVhY2gsICIrYWdlX2F0X2RpYWdub3Npc195ZWFycyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlLnBhdGgocmVzdWx0c19kaXIsIHBhc3RlMCgiY294X0VGU19pbnRlcmFjdGlvbl90ZXJtc19yZXNlY3Rpb25fbGdnX2dyb3VwX2NsdXN0ZXJfc3BsaWNlb3NvbWVfZ3N2YV9zY29yZV8iLCBlYWNoLCAiLlJEUyIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm11bHRpdmFyaWF0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXJzX2NvbCA9ICJFRlNfeWVhcnMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0dXNfY29sID0gIkVGU19zdGF0dXMiKQogIAogIGludF9mb3Jlc3RfZWZzIDwtIHBsb3RGb3Jlc3QocmVhZFJEUyhmaWxlLnBhdGgocmVzdWx0c19kaXIsIHBhc3RlMCgiY294X0VGU19pbnRlcmFjdGlvbl90ZXJtc19yZXNlY3Rpb25fbGdnX2dyb3VwX2NsdXN0ZXJfc3BsaWNlb3NvbWVfZ3N2YV9zY29yZV8iLCBlYWNoLCAiLlJEUyIpKSkpCiAgCiAgaW50X2ZvcmVzdF9lZnMKICAKICBnZ3NhdmUoZmlsZS5wYXRoKHBsb3RfZGlyLCBwYXN0ZTAoImNveF9FRlNfaW50ZXJhY3Rpb25fdGVybXNfcmVzZWN0aW9uX2xnZ19ncm91cF9jbHVzdGVyX3NwbGljZW9zb21lX2dzdmFfc2NvcmVfIiwgZWFjaCwgIi5wZGYiKSksCiAgICAgICAgIGludF9mb3Jlc3RfZWZzLAogICAgICAgICB3aWR0aCA9IDEwLCBoZWlnaHQgPSA2LCB1bml0cyA9ICJpbiIsCiAgICAgICAgIGRldmljZSA9ICJwZGYiKQp9CiAgCgoKYWRkX21vZGVsX2VmcyA8LSBmaXRfc2F2ZV9tb2RlbChtZXRhZGF0YVshbWV0YWRhdGEkZXh0ZW50X29mX3R1bW9yX3Jlc2VjdGlvbiAlaW4lIGMoIk5vdCBSZXBvcnRlZCIsICJVbmF2YWlsYWJsZSIpLF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlcm1zID0gImV4dGVudF9vZl90dW1vcl9yZXNlY3Rpb24rbGdnX2dyb3VwK2NsdXN0ZXIrYWdlX2F0X2RpYWdub3Npc195ZWFycytzcGxpY2Vvc29tZV9nc3ZhX3Njb3JlK0NMSzFfRXg0X1RQTSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlLnBhdGgocmVzdWx0c19kaXIsICJjb3hfRUZTX2FkZGl0aXZlX3Rlcm1zX3Jlc2VjdGlvbl9sZ2dfZ3JvdXBfY2x1c3Rlcl9zcGxpY2Vvc29tZV9zY29yZV9DTEsxX0V4NF9UUE0uUkRTIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibXVsdGl2YXJpYXRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXJzX2NvbCA9ICJFRlNfeWVhcnMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHVzX2NvbCA9ICJFRlNfc3RhdHVzIikKCmZvcmVzdF9lZnMgPC0gcGxvdEZvcmVzdChyZWFkUkRTKGZpbGUucGF0aChyZXN1bHRzX2RpciwgImNveF9FRlNfYWRkaXRpdmVfdGVybXNfcmVzZWN0aW9uX2xnZ19ncm91cF9jbHVzdGVyX3NwbGljZW9zb21lX3Njb3JlX0NMSzFfRXg0X1RQTS5SRFMiKSkpCgpmb3Jlc3RfZWZzCgpnZ3NhdmUoZmlsZS5wYXRoKHBsb3RfZGlyLCAiZm9yZXN0X2FkZF9FRlNfcmVzZWN0aW9uX2xnZ19ncm91cF9jbHVzdGVyX2Fzc2lnbm1lbnRfc3BsaWNlb3NvbWVfc2NvcmVfQ0xLMV9FeDRfVFBNLnBkZiIpLAogICAgICAgZm9yZXN0X2VmcywKICAgICAgIHdpZHRoID0gMTAsIGhlaWdodCA9IDYsIHVuaXRzID0gImluIiwKICAgICAgIGRldmljZSA9ICJwZGYiKQoKCmFkZF9tb2RlbF9vcyA8LSBmaXRfc2F2ZV9tb2RlbChtZXRhZGF0YVshbWV0YWRhdGEkZXh0ZW50X29mX3R1bW9yX3Jlc2VjdGlvbiAlaW4lIGMoIk5vdCBSZXBvcnRlZCIsICJVbmF2YWlsYWJsZSIpLF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlcm1zID0gImV4dGVudF9vZl90dW1vcl9yZXNlY3Rpb24rbGdnX2dyb3VwK2NsdXN0ZXIrYWdlX2F0X2RpYWdub3Npc195ZWFycytzcGxpY2Vvc29tZV9nc3ZhX3Njb3JlK0NMSzFfRXg0X1RQTSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlLnBhdGgocmVzdWx0c19kaXIsICJjb3hfT1NfYWRkaXRpdmVfdGVybXNfcmVzZWN0aW9uX2xnZ19ncm91cF9jbHVzdGVyX3NwbGljZW9zb21lX3Njb3JlX0NMSzFfRXg0X1RQTS5SRFMiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJtdWx0aXZhcmlhdGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhcnNfY29sID0gIkVGU195ZWFycyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0dXNfY29sID0gIkVGU19zdGF0dXMiKQoKZm9yZXN0X29zIDwtIHBsb3RGb3Jlc3QocmVhZFJEUyhmaWxlLnBhdGgocmVzdWx0c19kaXIsICJjb3hfT1NfYWRkaXRpdmVfdGVybXNfcmVzZWN0aW9uX2xnZ19ncm91cF9jbHVzdGVyX3NwbGljZW9zb21lX3Njb3JlX0NMSzFfRXg0X1RQTS5SRFMiKSkpCgpmb3Jlc3Rfb3MKCmdnc2F2ZShmaWxlLnBhdGgocGxvdF9kaXIsICJmb3Jlc3RfYWRkX09TX3Jlc2VjdGlvbl9sZ2dfZ3JvdXBfY2x1c3Rlcl9hc3NpZ25tZW50X3NwbGljZW9zb21lX3Njb3JlX0NMSzFfRXg0X1RQTS5wZGYiKSwKICAgICAgIGZvcmVzdF9lZnMsCiAgICAgICB3aWR0aCA9IDEwLCBoZWlnaHQgPSA2LCB1bml0cyA9ICJpbiIsCiAgICAgICBkZXZpY2UgPSAicGRmIikKCgpgYGAKCgoKRmlsdGVyIGZvciBjbHVzdGVycwoKYGBge3J9CgpjbHVzdGVyX2xpc3QgPC0gdW5pcXVlKG1ldGFkYXRhJGNsdXN0ZXIpCgpmb3IgKGVhY2ggaW4gY2x1c3Rlcl9saXN0KSB7CmNsdXN0ZXJfZGYgPC0gbWV0YWRhdGEgJT4lCiAgZHBseXI6OmZpbHRlcihjbHVzdGVyID09IGVhY2gsCiAgICAgICAgICAgICAgICAhaXMubmEoRUZTX2RheXMpKSAlPiUKICBkcGx5cjo6bXV0YXRlKENMSzFfVFBNX2dyb3VwID0gY2FzZV93aGVuKAogICAgICBDTEsxX0V4NF9UUE0gPiBzdW1tYXJ5KENMSzFfRXg0X1RQTSlbIjNyZCBRdS4iXSB+ICJIaWdoIENMSzEgVFBNIiwKICAgICAgQ0xLMV9FeDRfVFBNIDwgc3VtbWFyeShDTEsxX0V4NF9UUE0pWyIxc3QgUXUuIl0gfiAiTG93IENMSzEgVFBNIiwKICAgICAgVFJVRSB+IE5BX2NoYXJhY3Rlcl8pLAogICAgICBDTEsxX1BTSV9ncm91cCA9IGNhc2Vfd2hlbihDTEsxX2V4NF9QU0kgPiBzdW1tYXJ5KENMSzFfZXg0X1BTSSlbIjNyZCBRdS4iXSB+ICJIaWdoIENMSzEgUFNJIiwKICAgICAgQ0xLMV9leDRfUFNJIDwgc3VtbWFyeShDTEsxX2V4NF9QU0kpWyIxc3QgUXUuIl0gfiAiTG93IENMSzEgUFNJIiwKICAgICAgVFJVRSB+IE5BX2NoYXJhY3Rlcl8KICAgICkpICU+JQogIGRwbHlyOjptdXRhdGUoQ0xLMV9UUE1fZ3JvdXAgPSBmY3RfcmVsZXZlbChDTEsxX1RQTV9ncm91cCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoIkxvdyBDTEsxIFRQTSIsICJIaWdoIENMSzEgVFBNIikpLAogICAgICAgICAgICAgICAgQ0xLMV9QU0lfZ3JvdXAgPSBmY3RfcmVsZXZlbChDTEsxX1BTSV9ncm91cCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoIkxvdyBDTEsxIFBTSSIsICJIaWdoIENMSzEgUFNJIikpKSAlPiUKICMgY29sbGFwc2UgZ3JvdXBzIHdoaWNoIGRvIG5vdCBoYXZlIG1pbiBOCiAgIGRwbHlyOjptdXRhdGUoCiAgICBwbG90X2dyb3VwID0gZm9yY2F0czo6ZmN0X2Ryb3AocGxvdF9ncm91cCksCiAgICBwbG90X2dyb3VwID0gZm9yY2F0czo6ZmN0X2x1bXBfbWluKHBsb3RfZ3JvdXAsIG1pbiA9IDMsIG90aGVyX2xldmVsID0gIkNvbGxhcHNlZCIpCiAgKQoKIHNhZmVfZWFjaCA8LSBnc3ViKCJbXkEtWmEtejAtOV8tXSsiLCAiXyIsIGVhY2gpCgojIEdlbmVyYXRlIEtNIG1vZGVscyB3aXRoIGBDTEsxX1RQTV9ncm91cGAgYXMgY292YXJpYXRlCiMgR2VuZXJhdGUga2FwbGFuIG1laWVyIHN1cnZpdmFsIG1vZGVscyBmb3IgT1MgYW5kIEVGUywgYW5kIHNhdmUgb3V0cHV0cwpjbHVzdGVyX2Nsa190cG1fa2FwX29zIDwtIHN1cnZpdmFsX2FuYWx5c2lzKAogIG1ldGFkYXRhICA9IGNsdXN0ZXJfZGYgJT4lIAogICAgZHBseXI6OmZpbHRlcighaXMubmEoQ0xLMV9UUE1fZ3JvdXApKSwKICBpbmRfdmFyID0gIkNMSzFfVFBNX2dyb3VwIiwKICB0ZXN0ID0gImthcC5tZWllciIsCiAgbWV0YWRhdGFfc2FtcGxlX2NvbCA9ICJLaWRzX0ZpcnN0X0Jpb3NwZWNpbWVuX0lEIiwKICBkYXlzX2NvbCA9ICJPU19kYXlzIiwKICBzdGF0dXNfY29sID0gIk9TX3N0YXR1cyIKKQoKcmVhZHI6OndyaXRlX3JkcyhjbHVzdGVyX2Nsa190cG1fa2FwX29zLAogICAgICAgICAgICAgICAgIGZpbGUucGF0aChyZXN1bHRzX2RpciwgcGFzdGUwKCAibG9ncmFua18iLCBzYWZlX2VhY2gsICJfT1NfY2xrMV90cG1fZ3JvdXAuUkRTIikpKQoKY2x1c3Rlcl9jbGtfdHBtX2thcF9lZnMgPC0gc3Vydml2YWxfYW5hbHlzaXMoCiAgbWV0YWRhdGEgID0gY2x1c3Rlcl9kZiAlPiUgCiAgICBkcGx5cjo6ZmlsdGVyKCFpcy5uYShDTEsxX1RQTV9ncm91cCkpLAogIGluZF92YXIgPSAiQ0xLMV9UUE1fZ3JvdXAiLAogIHRlc3QgPSAia2FwLm1laWVyIiwKICBtZXRhZGF0YV9zYW1wbGVfY29sID0gIktpZHNfRmlyc3RfQmlvc3BlY2ltZW5fSUQiLAogIGRheXNfY29sID0gIkVGU19kYXlzIiwKICBzdGF0dXNfY29sID0gIkVGU19zdGF0dXMiCikKCnJlYWRyOjp3cml0ZV9yZHMoY2x1c3Rlcl9jbGtfdHBtX2thcF9lZnMsCiAgICAgICAgICAgICAgICAgZmlsZS5wYXRoKHJlc3VsdHNfZGlyLCBwYXN0ZTAoICJsb2dyYW5rXyIsIHNhZmVfZWFjaCwgIl9FRlNfY2xrMV90cG1fZ3JvdXAuUkRTIikpKQoKIyBHZW5lcmF0ZSBLTSBtb2RlbHMgd2l0aCBgQ0xLMV9QU0lfZ3JvdXBgIGFzIGNvdmFyaWF0ZQojIEdlbmVyYXRlIGthcGxhbiBtZWllciBzdXJ2aXZhbCBtb2RlbHMgZm9yIE9TIGFuZCBFRlMsIGFuZCBzYXZlIG91dHB1dHMKY2x1c3Rlcl9jbGtfcHNpX2thcF9vcyA8LSBzdXJ2aXZhbF9hbmFseXNpcygKICBtZXRhZGF0YSAgPSBjbHVzdGVyX2RmICU+JSAKICAgIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKENMSzFfUFNJX2dyb3VwKSksCiAgaW5kX3ZhciA9ICJDTEsxX1BTSV9ncm91cCIsCiAgdGVzdCA9ICJrYXAubWVpZXIiLAogIG1ldGFkYXRhX3NhbXBsZV9jb2wgPSAiS2lkc19GaXJzdF9CaW9zcGVjaW1lbl9JRCIsCiAgZGF5c19jb2wgPSAiT1NfZGF5cyIsCiAgc3RhdHVzX2NvbCA9ICJPU19zdGF0dXMiCikKCnJlYWRyOjp3cml0ZV9yZHMoY2x1c3Rlcl9jbGtfcHNpX2thcF9vcywKICAgICAgICAgICAgICAgICBmaWxlLnBhdGgocmVzdWx0c19kaXIsIHBhc3RlMCggImxvZ3JhbmtfIiwgc2FmZV9lYWNoLCAiX09TX2NsazFfcHNpX2dyb3VwLlJEUyIpKSkKCmNsdXN0ZXJfY2xrX3BzaV9rYXBfZWZzIDwtIHN1cnZpdmFsX2FuYWx5c2lzKAogIG1ldGFkYXRhICA9IGNsdXN0ZXJfZGYgJT4lIAogICAgZHBseXI6OmZpbHRlcighaXMubmEoQ0xLMV9QU0lfZ3JvdXApKSwKICBpbmRfdmFyID0gIkNMSzFfUFNJX2dyb3VwIiwKICB0ZXN0ID0gImthcC5tZWllciIsCiAgbWV0YWRhdGFfc2FtcGxlX2NvbCA9ICJLaWRzX0ZpcnN0X0Jpb3NwZWNpbWVuX0lEIiwKICBkYXlzX2NvbCA9ICJFRlNfZGF5cyIsCiAgc3RhdHVzX2NvbCA9ICJFRlNfc3RhdHVzIgopCgpyZWFkcjo6d3JpdGVfcmRzKGNsdXN0ZXJfY2xrX3BzaV9rYXBfZWZzLAogICAgICAgICAgICAgICAgIGZpbGUucGF0aChyZXN1bHRzX2RpciwgcGFzdGUwKCAibG9ncmFua18iLCBzYWZlX2VhY2gsICJfRUZTX2NsazFfcHNpX2dyb3VwLlJEUyIpKSkKCiMgR2VuZXJhdGUgY2x1c3RlciBLTSBTSV9ncm91cCBwbG90cwoKa21fY2x1c3Rlcl9jbGtfdHBtX29zX3Bsb3QgPC0gcGxvdEtNKG1vZGVsID0gY2x1c3Rlcl9jbGtfdHBtX2thcF9vcywKICAgICAgICAgICAgICAgICAgICB2YXJpYWJsZSA9ICJDTEsxX1RQTV9ncm91cCIsCiAgICAgICAgICAgICAgICAgICAgY29tYmluZWQgPSBGLCAKICAgICAgICAgICAgICAgICAgICB0aXRsZSA9IHBhc3RlMChlYWNoLCAiLCBvdmVyYWxsIHN1cnZpdmFsIiksCiAgICAgICAgICAgICAgICAgICAgcF9wb3MgPSAidG9wcmlnaHQiKQoKZ2dzYXZlKGZpbGUucGF0aChwbG90X2RpciwgcGFzdGUwKCJrbV8iLCBzYWZlX2VhY2gsICJfT1NfY2xrMV90cG1fZ3JvdXAucGRmIikpLAogICAgICAga21fY2x1c3Rlcl9jbGtfdHBtX29zX3Bsb3QsCiAgICAgICB3aWR0aCA9IDgsIGhlaWdodCA9IDUsIHVuaXRzID0gImluIiwKICAgICAgIGRldmljZSA9ICJwZGYiKQoKa21fY2x1c3Rlcl9jbGsxX3RwbV9lZnNfcGxvdCA8LSBwbG90S00obW9kZWwgPSBjbHVzdGVyX2Nsa190cG1fa2FwX2VmcywKICAgICAgICAgICAgICAgICAgICB2YXJpYWJsZSA9ICJDTEsxX1RQTV9ncm91cCIsCiAgICAgICAgICAgICAgICAgICAgY29tYmluZWQgPSBGLCAKICAgICAgICAgICAgICAgICAgICB0aXRsZSA9IHBhc3RlMChlYWNoLCAiLCBldmVudC1mcmVlIHN1cnZpdmFsIiksCiAgICAgICAgICAgICAgICAgICAgcF9wb3MgPSAidG9wcmlnaHQiKQoKZ2dzYXZlKGZpbGUucGF0aChwbG90X2RpciwgcGFzdGUwKCAia21fIiwgc2FmZV9lYWNoLCAiX0VGU19jbGsxX3RwbV9ncm91cC5wZGYiKSksIAogICAgICAga21fY2x1c3Rlcl9jbGsxX3RwbV9lZnNfcGxvdCwKICAgICAgIHdpZHRoID0gOCwgaGVpZ2h0ID0gNSwgdW5pdHMgPSAiaW4iLAogICAgICAgZGV2aWNlID0gInBkZiIpCgprbV9jbHVzdGVyX2NsazFfcHNpX29zX3Bsb3QgPC0gcGxvdEtNKG1vZGVsID0gY2x1c3Rlcl9jbGtfcHNpX2thcF9vcywKICAgICAgICAgICAgICAgICAgICB2YXJpYWJsZSA9ICJDTEsxX1BTSV9ncm91cCIsCiAgICAgICAgICAgICAgICAgICAgY29tYmluZWQgPSBGLCAKICAgICAgICAgICAgICAgICAgICB0aXRsZSA9IHBhc3RlMChlYWNoLCAiLCBvdmVyYWxsIHN1cnZpdmFsIiksCiAgICAgICAgICAgICAgICAgICAgcF9wb3MgPSAidG9wcmlnaHQiKQoKZ2dzYXZlKGZpbGUucGF0aChwbG90X2RpciwgcGFzdGUwKCAia21fIiwgc2FmZV9lYWNoLCAiX09TX2NsazFfcHNpX2dyb3VwLnBkZiIpKSwKICAgICAgIGttX2NsdXN0ZXJfY2xrMV9wc2lfb3NfcGxvdCwKICAgICAgIHdpZHRoID0gOCwgaGVpZ2h0ID0gNSwgdW5pdHMgPSAiaW4iLAogICAgICAgZGV2aWNlID0gInBkZiIpCgprbV9jbHVzdGVyX2NsazFfcHNpX2Vmc19wbG90IDwtIHBsb3RLTShtb2RlbCA9IGNsdXN0ZXJfY2xrX3BzaV9rYXBfZWZzLAogICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlID0gIkNMSzFfUFNJX2dyb3VwIiwKICAgICAgICAgICAgICAgICAgICBjb21iaW5lZCA9IEYsIAogICAgICAgICAgICAgICAgICAgIHRpdGxlID0gcGFzdGUwKGVhY2gsICIsIGV2ZW50LWZyZWUgc3Vydml2YWwiKSwKICAgICAgICAgICAgICAgICAgICBwX3BvcyA9ICJ0b3ByaWdodCIpCgpnZ3NhdmUoZmlsZS5wYXRoKHBsb3RfZGlyLCBwYXN0ZTAoImttXyIsIHNhZmVfZWFjaCwgIl9FRlNfY2xrMV9wc2lfZ3JvdXAucGRmIikpLCAKICAgICAgIGttX2NsdXN0ZXJfY2xrMV9wc2lfZWZzX3Bsb3QsCiAgICAgICB3aWR0aCA9IDgsIGhlaWdodCA9IDUsIHVuaXRzID0gImluIiwKICAgICAgIGRldmljZSA9ICJwZGYiKQoKIyBBc3Nlc3MgRUZTIGFuZCBPUyBieSBDTEsxIFRQTSBncm91cCBpbiBtdWx0aXZhcmlhdGUgbW9kZWxzIGFuZCBnZW5lcmF0ZSBmb3Jlc3QgcGxvdHMKCmFkZF9tb2RlbF9jbHVzdGVyX2VmcyA8LSBmaXRfc2F2ZV9tb2RlbChjbHVzdGVyX2RmICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcGx5cjo6ZmlsdGVyKGV4dGVudF9vZl90dW1vcl9yZXNlY3Rpb24gIT0gIlVuYXZhaWxhYmxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENMSzFfVFBNX2dyb3VwICVpbiUgYygiSGlnaCBDTEsxIFRQTSIsICJMb3cgQ0xLMSBUUE0iKSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRwbHlyOjptdXRhdGUocGxvdF9ncm91cCA9IGZvcmNhdHM6OmZjdF9yZWxldmVsKHBsb3RfZ3JvdXAsICJMb3ctZ3JhZGUgZ2xpb21hIiwgYWZ0ZXIgPSAwKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlcm1zID0gImV4dGVudF9vZl90dW1vcl9yZXNlY3Rpb24rYWdlX2F0X2RpYWdub3Npc195ZWFycytwbG90X2dyb3VwK0NMSzFfVFBNX2dyb3VwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGUucGF0aChyZXN1bHRzX2RpciwgcGFzdGUwKCAiY294X0VGU19hZGRpdGl2ZV90ZXJtc19zdWJ0eXBlXyIsIHNhZmVfZWFjaCwgIl9jbGsxX3RwbV9ncm91cC5SRFMiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibXVsdGl2YXJpYXRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXJzX2NvbCA9ICJFRlNfeWVhcnMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHVzX2NvbCA9ICJFRlNfc3RhdHVzIikKCmZvcmVzdF9jbHVzdGVyX2NsazFfZWZzIDwtIHBsb3RGb3Jlc3QocmVhZFJEUyhmaWxlLnBhdGgocmVzdWx0c19kaXIsIHBhc3RlMCgiY294X0VGU19hZGRpdGl2ZV90ZXJtc19zdWJ0eXBlXyIsIHNhZmVfZWFjaCwgIl9jbGsxX3RwbV9ncm91cC5SRFMiKSkpKQoKZ2dzYXZlKGZpbGUucGF0aChwbG90X2RpciwgcGFzdGUwKCJmb3Jlc3RfYWRkX0VGU18iLCBzYWZlX2VhY2gsICJfaGlzdG9sb2d5X3Jlc2VjdGlvbl9jbGsxX3RwbV9ncm91cC5wZGYiKSksCiAgICAgICBmb3Jlc3RfY2x1c3Rlcl9jbGsxX2VmcywKICAgICAgIHdpZHRoID0gOSwgaGVpZ2h0ID0gNCwgdW5pdHMgPSAiaW4iLAogICAgICAgZGV2aWNlID0gInBkZiIpCgphZGRfbW9kZWxfY2x1c3Rlcl9vcyA8LSBmaXRfc2F2ZV9tb2RlbChjbHVzdGVyX2RmICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHBseXI6OmZpbHRlcighZXh0ZW50X29mX3R1bW9yX3Jlc2VjdGlvbiAlaW4lIGMoIk5vdCBSZXBvcnRlZCIsICJVbmF2YWlsYWJsZSIpKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHBseXI6Om11dGF0ZShwbG90X2dyb3VwID0gZm9yY2F0czo6ZmN0X3JlbGV2ZWwocGxvdF9ncm91cCwgIkxvdy1ncmFkZSBnbGlvbWEiLCBhZnRlciA9IDApKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVybXMgPSAiZXh0ZW50X29mX3R1bW9yX3Jlc2VjdGlvbithZ2VfYXRfZGlhZ25vc2lzX3llYXJzK3Bsb3RfZ3JvdXArQ0xLMV9UUE1fZ3JvdXAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZS5wYXRoKHJlc3VsdHNfZGlyLCBwYXN0ZTAoICJjb3hfT1NfYWRkaXRpdmVfdGVybXNfc3VidHlwZV8iLCBzYWZlX2VhY2gsICJfY2xrMV90cG1fZ3JvdXAuUkRTIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm11bHRpdmFyaWF0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyc19jb2wgPSAiT1NfeWVhcnMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHVzX2NvbCA9ICJPU19zdGF0dXMiKQoKZm9yZXN0X2NsdXN0ZXJfY2xrMV9vcyA8LSBwbG90Rm9yZXN0KHJlYWRSRFMoZmlsZS5wYXRoKHJlc3VsdHNfZGlyLCBwYXN0ZTAoICJjb3hfT1NfYWRkaXRpdmVfdGVybXNfc3VidHlwZV8iLCBzYWZlX2VhY2gsICJfY2xrMV90cG1fZ3JvdXAuUkRTIikpKSkKCmdnc2F2ZShmaWxlLnBhdGgocGxvdF9kaXIsIHBhc3RlMCggImZvcmVzdF9hZGRfT1NfIiwgc2FmZV9lYWNoLCAiX2hpc3RvbG9neV9yZXNlY3Rpb25fY2xrMV90cG1fZ3JvdXAucGRmIikpLAogICAgICAgZm9yZXN0X2NsdXN0ZXJfY2xrMV9vcywKICAgICAgIHdpZHRoID0gOSwgaGVpZ2h0ID0gNCwgdW5pdHMgPSAiaW4iLAogICAgICAgZGV2aWNlID0gInBkZiIpCgojQXNzZXNzIEVGUyBhbmQgT1MgYnkgQ0xLMSBQU0kgZ3JvdXAgaW4gbXVsdGl2YXJpYXRlIG1vZGVscyBhbmQgZ2VuZXJhdGUgZm9yZXN0IHBsb3RzCgphZGRfbW9kZWxfY2x1c3Rlcl9lZnMgPC0gZml0X3NhdmVfbW9kZWwoY2x1c3Rlcl9kZiAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHBseXI6OmZpbHRlcihleHRlbnRfb2ZfdHVtb3JfcmVzZWN0aW9uICE9ICJVbmF2YWlsYWJsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDTEsxX1BTSV9ncm91cCAlaW4lIGMoIkhpZ2ggQ0xLMSBQU0kiLCAiTG93IENMSzEgUFNJIikpJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRwbHlyOjptdXRhdGUocGxvdF9ncm91cCA9IGZvcmNhdHM6OmZjdF9yZWxldmVsKHBsb3RfZ3JvdXAsICJMb3ctZ3JhZGUgZ2xpb21hIiwgYWZ0ZXIgPSAwKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlcm1zID0gImV4dGVudF9vZl90dW1vcl9yZXNlY3Rpb24rYWdlX2F0X2RpYWdub3Npc195ZWFycytwbG90X2dyb3VwK0NMSzFfUFNJX2dyb3VwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGUucGF0aChyZXN1bHRzX2RpciwgcGFzdGUwKCAiY294X0VGU19hZGRpdGl2ZV90ZXJtc19zdWJ0eXBlXyIsIHNhZmVfZWFjaCwgIl9jbGsxX3BzaV9ncm91cC5SRFMiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibXVsdGl2YXJpYXRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXJzX2NvbCA9ICJFRlNfeWVhcnMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHVzX2NvbCA9ICJFRlNfc3RhdHVzIikKCmZvcmVzdF9jbHVzdGVyX2NsazFfZWZzIDwtIHBsb3RGb3Jlc3QocmVhZFJEUyhmaWxlLnBhdGgocmVzdWx0c19kaXIsIHBhc3RlMCggImNveF9FRlNfYWRkaXRpdmVfdGVybXNfc3VidHlwZV8iLCBzYWZlX2VhY2gsICJfY2xrMV9wc2lfZ3JvdXAuUkRTIikpKSkKCmdnc2F2ZShmaWxlLnBhdGgocGxvdF9kaXIsIHBhc3RlMCggImZvcmVzdF9hZGRfRUZTXyIsIHNhZmVfZWFjaCwgIl9oaXN0b2xvZ3lfcmVzZWN0aW9uX2NsazFfcHNpX2dyb3VwLnBkZiIpKSwKICAgICAgIGZvcmVzdF9jbHVzdGVyX2NsazFfZWZzLAogICAgICAgd2lkdGggPSA5LCBoZWlnaHQgPSA0LCB1bml0cyA9ICJpbiIsCiAgICAgICBkZXZpY2UgPSAicGRmIikKCmFkZF9tb2RlbF9jbHVzdGVyX29zIDwtIGZpdF9zYXZlX21vZGVsKGNsdXN0ZXJfZGYgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcGx5cjo6ZmlsdGVyKCFleHRlbnRfb2ZfdHVtb3JfcmVzZWN0aW9uICVpbiUgYygiTm90IFJlcG9ydGVkIiwgIlVuYXZhaWxhYmxlIikpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcGx5cjo6bXV0YXRlKHBsb3RfZ3JvdXAgPSBmb3JjYXRzOjpmY3RfcmVsZXZlbChwbG90X2dyb3VwLCAiTG93LWdyYWRlIGdsaW9tYSIsIGFmdGVyID0gMCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXJtcyA9ICJleHRlbnRfb2ZfdHVtb3JfcmVzZWN0aW9uK2FnZV9hdF9kaWFnbm9zaXNfeWVhcnMrcGxvdF9ncm91cCtDTEsxX1BTSV9ncm91cCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlLnBhdGgocmVzdWx0c19kaXIsIHBhc3RlMCggImNveF9PU19hZGRpdGl2ZV90ZXJtc19zdWJ0eXBlXyIsIHNhZmVfZWFjaCwgIl9jbGsxX3BzaV9ncm91cC5SRFMiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibXVsdGl2YXJpYXRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXJzX2NvbCA9ICJPU195ZWFycyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0dXNfY29sID0gIk9TX3N0YXR1cyIpCgpmb3Jlc3RfY2x1c3Rlcl9jbGsxX29zIDwtIHBsb3RGb3Jlc3QocmVhZFJEUyhmaWxlLnBhdGgocmVzdWx0c19kaXIsIHBhc3RlMCggImNveF9PU19hZGRpdGl2ZV90ZXJtc19zdWJ0eXBlXyIsIHNhZmVfZWFjaCwgIl9jbGsxX3BzaV9ncm91cC5SRFMiKSkpKQoKZ2dzYXZlKGZpbGUucGF0aChwbG90X2RpciwgcGFzdGUwKCAiZm9yZXN0X2FkZF9PU18iLCBzYWZlX2VhY2gsICJfaGlzdG9sb2d5X3Jlc2VjdGlvbl9jbGsxX3BzaV9ncm91cC5wZGYiKSksCiAgICAgICBmb3Jlc3RfY2x1c3Rlcl9jbGsxX29zLAogICAgICAgd2lkdGggPSA5LCBoZWlnaHQgPSA0LCB1bml0cyA9ICJpbiIsCiAgICAgICBkZXZpY2UgPSAicGRmIikKCiMgQXNzZXNzIEVGUyBhbmQgT1MgYnkgQ0xLMSBleCA0IFRQTSBpbiBtdWx0aXZhcmlhdGUgbW9kZWxzIGFuZCBnZW5lcmF0ZSBmb3Jlc3QgcGxvdHMKCmFkZF9tb2RlbF9jbHVzdGVyX2VmcyA8LSBmaXRfc2F2ZV9tb2RlbChjbHVzdGVyX2RmICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcGx5cjo6ZmlsdGVyKGV4dGVudF9vZl90dW1vcl9yZXNlY3Rpb24gIT0gIlVuYXZhaWxhYmxlIikgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRwbHlyOjptdXRhdGUocGxvdF9ncm91cCA9IGZvcmNhdHM6OmZjdF9yZWxldmVsKHBsb3RfZ3JvdXAsICJMb3ctZ3JhZGUgZ2xpb21hIiwgYWZ0ZXIgPSAwKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlcm1zID0gImV4dGVudF9vZl90dW1vcl9yZXNlY3Rpb24rYWdlX2F0X2RpYWdub3Npc195ZWFycytwbG90X2dyb3VwK0NMSzFfRXg0X1RQTSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlLnBhdGgocmVzdWx0c19kaXIsIHBhc3RlMCggImNveF9FRlNfYWRkaXRpdmVfdGVybXNfc3VidHlwZV8iLCBzYWZlX2VhY2gsICJfY2xrMV90cG0uUkRTIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm11bHRpdmFyaWF0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyc19jb2wgPSAiRUZTX3llYXJzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXR1c19jb2wgPSAiRUZTX3N0YXR1cyIpCgpmb3Jlc3RfY2x1c3Rlcl9jbGsxX2VmcyA8LSBwbG90Rm9yZXN0KHJlYWRSRFMoZmlsZS5wYXRoKHJlc3VsdHNfZGlyLCBwYXN0ZTAoICJjb3hfRUZTX2FkZGl0aXZlX3Rlcm1zX3N1YnR5cGVfIiwgc2FmZV9lYWNoLCAiX2NsazFfdHBtLlJEUyIpKSkpCgpnZ3NhdmUoZmlsZS5wYXRoKHBsb3RfZGlyLCBwYXN0ZTAoICJmb3Jlc3RfYWRkX0VGU18iLCBzYWZlX2VhY2gsICJfaGlzdG9sb2d5X3Jlc2VjdGlvbl9jbGsxX3RwbS5wZGYiKSksCiAgICAgICBmb3Jlc3RfY2x1c3Rlcl9jbGsxX2VmcywKICAgICAgIHdpZHRoID0gOSwgaGVpZ2h0ID0gNCwgdW5pdHMgPSAiaW4iLAogICAgICAgZGV2aWNlID0gInBkZiIpCgphZGRfbW9kZWxfY2x1c3Rlcl9vcyA8LSBmaXRfc2F2ZV9tb2RlbChjbHVzdGVyX2RmICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHBseXI6OmZpbHRlcighZXh0ZW50X29mX3R1bW9yX3Jlc2VjdGlvbiAlaW4lIGMoIk5vdCBSZXBvcnRlZCIsICJVbmF2YWlsYWJsZSIpKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHBseXI6Om11dGF0ZShwbG90X2dyb3VwID0gZm9yY2F0czo6ZmN0X3JlbGV2ZWwocGxvdF9ncm91cCwgIkxvdy1ncmFkZSBnbGlvbWEiLCBhZnRlciA9IDApKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVybXMgPSAiZXh0ZW50X29mX3R1bW9yX3Jlc2VjdGlvbithZ2VfYXRfZGlhZ25vc2lzX3llYXJzK3Bsb3RfZ3JvdXArQ0xLMV9FeDRfVFBNIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGUucGF0aChyZXN1bHRzX2RpciwgcGFzdGUwKCAiY294X09TX2FkZGl0aXZlX3Rlcm1zX3N1YnR5cGVfIiwgc2FmZV9lYWNoLCAiX2NsazFfdHBtLlJEUyIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJtdWx0aXZhcmlhdGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhcnNfY29sID0gIk9TX3llYXJzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXR1c19jb2wgPSAiT1Nfc3RhdHVzIikKCmZvcmVzdF9jbHVzdGVyX2NsazFfb3MgPC0gcGxvdEZvcmVzdChyZWFkUkRTKGZpbGUucGF0aChyZXN1bHRzX2RpciwgcGFzdGUwKCAiY294X09TX2FkZGl0aXZlX3Rlcm1zX3N1YnR5cGVfIiwgc2FmZV9lYWNoLCAiX2NsazFfdHBtLlJEUyIpKSkpCgpnZ3NhdmUoZmlsZS5wYXRoKHBsb3RfZGlyLCBwYXN0ZTAoICJmb3Jlc3RfYWRkX09TXyIsIHNhZmVfZWFjaCwgIl9oaXN0b2xvZ3lfcmVzZWN0aW9uX2NsazFfdHBtLnBkZiIpKSwKICAgICAgIGZvcmVzdF9jbHVzdGVyX2NsazFfb3MsCiAgICAgICB3aWR0aCA9IDksIGhlaWdodCA9IDQsIHVuaXRzID0gImluIiwKICAgICAgIGRldmljZSA9ICJwZGYiKQoKIyBBc3Nlc3MgRUZTIGFuZCBPUyBieSBDTEsxIGV4IDQgUFNJIGluIG11bHRpdmFyaWF0ZSBtb2RlbHMgYW5kIGdlbmVyYXRlIGZvcmVzdCBwbG90cwoKYWRkX21vZGVsX2NsdXN0ZXJfZWZzIDwtIGZpdF9zYXZlX21vZGVsKGNsdXN0ZXJfZGYgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRwbHlyOjpmaWx0ZXIoZXh0ZW50X29mX3R1bW9yX3Jlc2VjdGlvbiAhPSAiVW5hdmFpbGFibGUiKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHBseXI6Om11dGF0ZShwbG90X2dyb3VwID0gZm9yY2F0czo6ZmN0X3JlbGV2ZWwocGxvdF9ncm91cCwgIkxvdy1ncmFkZSBnbGlvbWEiLCBhZnRlciA9IDApKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVybXMgPSAiZXh0ZW50X29mX3R1bW9yX3Jlc2VjdGlvbithZ2VfYXRfZGlhZ25vc2lzX3llYXJzK3Bsb3RfZ3JvdXArQ0xLMV9leDRfUFNJIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGUucGF0aChyZXN1bHRzX2RpciwgcGFzdGUwKCAiY294X0VGU19hZGRpdGl2ZV90ZXJtc19zdWJ0eXBlXyIsIHNhZmVfZWFjaCwgIl9jbGsxX3BzaS5SRFMiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibXVsdGl2YXJpYXRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXJzX2NvbCA9ICJFRlNfeWVhcnMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHVzX2NvbCA9ICJFRlNfc3RhdHVzIikKCmZvcmVzdF9jbHVzdGVyX2NsazFfZWZzIDwtIHBsb3RGb3Jlc3QocmVhZFJEUyhmaWxlLnBhdGgocmVzdWx0c19kaXIsIHBhc3RlMCggImNveF9FRlNfYWRkaXRpdmVfdGVybXNfc3VidHlwZV8iLCBzYWZlX2VhY2gsICJfY2xrMV9wc2kuUkRTIikpKSkKCmdnc2F2ZShmaWxlLnBhdGgocGxvdF9kaXIsIHBhc3RlMCggImZvcmVzdF9hZGRfRUZTXyIsIHNhZmVfZWFjaCwgIl9oaXN0b2xvZ3lfcmVzZWN0aW9uX2NsazFfcHNpLnBkZiIpKSwKICAgICAgIGZvcmVzdF9jbHVzdGVyX2NsazFfZWZzLAogICAgICAgd2lkdGggPSA5LCBoZWlnaHQgPSA0LCB1bml0cyA9ICJpbiIsCiAgICAgICBkZXZpY2UgPSAicGRmIikKCmFkZF9tb2RlbF9jbHVzdGVyX29zIDwtIGZpdF9zYXZlX21vZGVsKGNsdXN0ZXJfZGYgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcGx5cjo6ZmlsdGVyKCFleHRlbnRfb2ZfdHVtb3JfcmVzZWN0aW9uICVpbiUgYygiTm90IFJlcG9ydGVkIiwgIlVuYXZhaWxhYmxlIikpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcGx5cjo6bXV0YXRlKHBsb3RfZ3JvdXAgPSBmb3JjYXRzOjpmY3RfcmVsZXZlbChwbG90X2dyb3VwLCAiTG93LWdyYWRlIGdsaW9tYSIsIGFmdGVyID0gMCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXJtcyA9ICJleHRlbnRfb2ZfdHVtb3JfcmVzZWN0aW9uK2FnZV9hdF9kaWFnbm9zaXNfeWVhcnMrcGxvdF9ncm91cCtDTEsxX2V4NF9QU0kiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZS5wYXRoKHJlc3VsdHNfZGlyLCBwYXN0ZTAoICJjb3hfT1NfYWRkaXRpdmVfdGVybXNfc3VidHlwZV8iLCBzYWZlX2VhY2gsICJfY2xrMV9wc2kuUkRTIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm11bHRpdmFyaWF0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyc19jb2wgPSAiT1NfeWVhcnMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHVzX2NvbCA9ICJPU19zdGF0dXMiKQoKZm9yZXN0X2NsdXN0ZXJfY2xrMV9vcyA8LSBwbG90Rm9yZXN0KHJlYWRSRFMoZmlsZS5wYXRoKHJlc3VsdHNfZGlyLCBwYXN0ZTAoICJjb3hfT1NfYWRkaXRpdmVfdGVybXNfc3VidHlwZV8iLCBzYWZlX2VhY2gsICJfY2xrMV9wc2kuUkRTIikpKSkKCmdnc2F2ZShmaWxlLnBhdGgocGxvdF9kaXIsIHBhc3RlMCggImZvcmVzdF9hZGRfT1NfIiwgZWFjaCwgIl9oaXN0b2xvZ3lfcmVzZWN0aW9uX2NsazFfcHNpLnBkZiIpKSwKICAgICAgIGZvcmVzdF9jbHVzdGVyX2NsazFfb3MsCiAgICAgICB3aWR0aCA9IDksIGhlaWdodCA9IDQsIHVuaXRzID0gImluIiwKICAgICAgIGRldmljZSA9ICJwZGYiKQp9CmBgYAoKCiMgUHJpbnQgc2Vzc2lvbiBJbmZvCgpgYGB7cn0Kc2Vzc2lvbkluZm8oKQpgYGA=